<?php
/*=============================================================================
|| ##################################################################
||	phpFoX Konsort
|| ##################################################################
||	
||	Copyright		: (C) 2005-2007 PHPFOX Limited a Reality Fox Creation
||	Contact			: info@phpfox.com
||
||	- phpFoX and all of its source code and files are protected by Copyright Laws. 
||
||	- The license for phpFoX permits you to install this software on a single domain (.com, .org, .net, etc.). 
||
||	- You may also not remove this copyright screen which shows the copyright information and credits for phpFoX (RealityFOX Creations). 
||
||	- phpFoX Konsort is NOT a FREE software - http://www.phpfox.com/license/
||
|| ##################################################################
=============================================================================*/

/* $File: ./include/classes/Filter.class.php, $Author:  $ */


/**
 * Filter class
 *
 *  Nikolay Severikov
 * @package core
 * @version 20 June 2006
 */

/*
 * -= HELP =-
 * 
 * Condition Types :
 *      FOR "like, =, =>, <=, <>"
 *          Additional Parameters :
 *              'def'      - default value (for first time show)
 *              'select'   - HTML select values
 *                           example : array ( '0' => '0 days',
 *                                             '1' => '1 day')
 *      FOR "range"
 *          Additional Parameters :
 *              'def_from' - default "FROM" value
 *              'def_to'   - default "TO" value
 *      FOR "date":
 *              'def_day'        - default "DAY"
 *              'def_month'      - default "MONTH"
 *              'def_year'       - default "YEAR"
 *              OR
 *              'def_timestamp'  - default UNIX timestamp
 *      FOR "date_range"
 *          Additional Parameters :
 *              'def_period'     - default period (@see $aPeriods)
 *              OR
 *              'def_day_from'   - default "FROM DAY" value
 *              'def_month_from' - default "FROM MONTH" value
 *              'def_year_from'  - default "FROM YEAR" value
 *              'def_day_to'     - default "TO DAY" value
 *              'def_month_to'   - default "TO MONTH" value
 *              'def_year_to'    - default "TO YEAR" value
 *      FOR "custiom conditions":
 *          Additional Parameters :
 *              'def'      - default value
 *
 * -- END OF HELP --
 */

class Filter
{
    
    /** Filter Name
     *
     * @var string
     */
    var $sFilterName = "";

    /** Filter data
     *
     * @var array
     */
    var $aData = array();
    
    /** Associative array of conditions
     * $alias => $internal_language
     *
     * @var array
     */
    var $aConditions = array();
    
    /** Associative array of HTML inputs
     *
     * @var mixed
     */
    var $aHtml = array();

    /**
     * Periods
     *
     * @var mixed
     */
    var $aPeriods = array(
                         '0' => array(
                                      'name' => 'Choose Range',
                                      'from' => '',
                                      'to'   => '',
                                     ),
                         '1' => array(
                                      'name' => 'Today',
                                      'from' => '-0 day',
                                      'to'   => '-0 day'
                                     ),
                         '2' => array(
                                      'name' => 'Yesterday',
                                      'from' => '-0 day',
                                      'to'   => '-1 day',
                                     ),
                         '3' => array(
                                      'name' => 'This week',
                                      'from' => 'last Monday',
                                      'to'   => '-0 day',
                                     ),
                         '4' => array(
                                      'name' => 'Last week',
                                      'from' => '-7 day',
                                      'to'   => 'last Monday'
                                     ),
                         '5' => array(
                                      'name' => 'This month',
                                      'from' => '-%dom% day',
                                      'to'   => '-0 day'
                                     ),
                         '6' => array(
                                      'name' => 'Last month',
                                      'from' => '-1 month',
                                      'to'   => '-%dom% day -1 day',
                                     ),
                         );
                         
    /** Year Period (for date_range and date)
     *
     * @example if 5, then start year range will be Current Year - 5, 
     *                end year range will be Current Year + 5
     * @var integer
     */
    var $iYearPeriod = 5;
    
    /** Class Constructor
     *
     * @return Filter
     */
    function Filter($sFilterName, $aConditions, $aCustomData = array())
    {
        $oReq = &App::getRequest();
        $this->sFilterName = $sFilterName;
        $this->aConditions = $aConditions;
        $this->aHtml       = array();
        $this->_preparePeriods();
        $sAction = $oReq->getAction();
        if ($sAction == $this->sFilterName.'_show')
        {
            $aData = $oReq->getArray($sFilterName);
            $this->set($aData);
        }
        elseif (count($aCustomData))
        {
            $this->set($aCustomData);
        }
        if ($sAction == $this->sFilterName.'_reset') $this->reset();
        $this->_initFilter();
        $this->_prepareHtml();
        if ($this->isActive())
        {
            $this->_prepareConditions();
            $this->_processConditions();
        }
        else
        {
            $this->aConditions = array();
        }
    }

    /** Submit filter data to filter and make conditions
     * 
     */
    function submitFilter()
    {
        $this->reset();
        //$this->_prepareConditions();
        return true;
    }

    /** Prepare periods for future use
     *
     */
    function _preparePeriods()
    {
        foreach ($this->aPeriods as $key=>$value)
        {
            $this->aPeriods[$key]['from'] = str_replace('%dom%', date('d')-1, $this->aPeriods[$key]['from']);
            $this->aPeriods[$key]['to'] = str_replace('%dom%', date('d')-1, $this->aPeriods[$key]['to']);
        }
    }
    
    /**
     * Is current filter active?
     *
     * @return bool
     */
    function isActive()
    {
        if (isset($_SESSION['filter'][$this->sFilterName]['__is_active__']))
        {
            return $_SESSION['filter'][$this->sFilterName]['__is_active__'];
        }
        else
        {
            return false;
        }
    }
    
    /**
     * Initialize/load filter
     *
     */
    function _initFilter()
    {
        if (!isset($_SESSION['filter'])) $_SESSION['filter'] = array();
        if (array_key_exists($this->sFilterName,$_SESSION['filter']))
        {
            $this->aData = $_SESSION['filter'][$this->sFilterName];
        }
        else
        {
            $this->_resetToDefault();
        }
    }
    
    /**
     * Resets a current filter
     *
     */
    function reset()
    {
        $this->_resetToDefault();
        if (isset($_SESSION['filter'][$this->sFilterName])) 
            $_SESSION['filter'][$this->sFilterName] = array();
        $this->disableFilter();
    }
    
    
    /**
     * Main functions that process conditions
     *
     */
    function _processConditions()
    {
        foreach ($this->aConditions as $key=>$value)
        {
            foreach ($this->aData as $key1=>$value1)
            {
                if (false !== strpos($value, '{$'.$key1.'}'))
                {
                    $value = str_replace('LIKE "%{$'.$key1.'}','LIKE "%'.DataBase::escapeLike($value1), $value);
                    $value = str_replace('{$'.$key1.'}',DataBase::escape($value1), $value);
                    $this->aConditions[$key] = $value;
                }
            }
        }
    }
    
    /** 
     * Set (turn on) filter.
     * 
     * @param array $aData - filter data (usually from POST)
     */
    function set($aData) 
    {
        $this->aData = $aData;
        $_SESSION['filter'][$this->sFilterName] = $this->aData;
        $this->activateFilter();
    }
    
    /**
     * Set filter status to active
     *
     */
    function activateFilter()
    {
        $_SESSION['filter'][$this->sFilterName]['__is_active__'] = true;
    }
    
    /**
     * Disables current filter (set it status to disabled)
     *
     */
    function disableFilter()
    {
        $_SESSION['filter'][$this->sFilterName]['__is_active__'] = false;
    }
    
    /**
     * Resets filter to default data
     *
     */
    function _resetToDefault()
    {
        foreach ($this->aConditions as $key=>$value)
        {
            $aOldValue = $value;
            if (is_array($value)) $value = $value['value'];
            switch ($value)
            {
                case 'date':
                    $nD = date('d');
                    $nM = date('n');
                    $nY = date('Y');
                    if (is_array($aOldValue))
                    {
                        if (array_key_exists('def_timestamp', $aOldValue))
                        {
                            $nD = date('d', $aOldValue['def_timestamp']);
                            $nM = date('n', $aOldValue['def_timestamp']);
                            $nY = date('Y', $aOldValue['def_timestamp']);
                        }
                        else
                        {
                            if (array_key_exists('def_day', $aOldValue))
                                $nD = $aOldValue['def_day'];
                            if (array_key_exists('def_month', $aOldValue))
                                $nM = $aOldValue['def_month'];
                            if (array_key_exists('def_year', $aOldValue))
                                $nY = $aOldValue['def_year'];
                        }
                    }
                    $this->aData[$key.'_day']   =  $nD;
                    $this->aData[$key.'_month'] =  $nM;
                    $this->aData[$key.'_year']  =  $nY;
                    break;
                case 'date_range':
                    $nDFrom = 1;
                    $nDTo   = 31;
                    $nMFrom = 1;
                    $nMTo   = 12;
                    $nYFrom = date('Y');
                    $nYTo   = date('Y');
                    if (is_array($aOldValue))
                    {
                        if (array_key_exists('def_period', $aOldValue) && array_key_exists($aOldValue['def_period'], $this->aPeriods))
                        {
                            $sFrom = $this->aPeriods[$aOldValue['def_period']]['from'];
                            $sTo   = $this->aPeriods[$aOldValue['def_period']]['to'];
                            if ($sFrom != "" && $sTo != "")
                            {
                                $this->aData[$key.'_period'] = $aOldValue['def_period'].' 1';
                                $nDFrom = date('d',strtotime($sFrom, strtotime($sTo)));
                                $nDTo   = date('d',strtotime($sTo));
                                $nMFrom = date('m',strtotime($sFrom, strtotime($sTo)));
                                $nMTo   = date('m',strtotime($sTo));
                                $nYFrom = date('Y',strtotime($sFrom, strtotime($sTo)));
                                $nYTo   = date('Y',strtotime($sTo));
                            }
                        }
                        else
                        {
                            if (array_key_exists('def_day_from', $aOldValue))
                                $nDFrom = $aOldValue['def_day_from'];
                            if (array_key_exists('def_day_to', $aOldValue))
                                $nDTo = $aOldValue['def_day_to'];
                            if (array_key_exists('def_month_from', $aOldValue))
                                $nMFrom = $aOldValue['def_month_from'];
                            if (array_key_exists('def_month_to', $aOldValue))
                                $nMTo = $aOldValue['def_month_to'];
                            if (array_key_exists('def_year_from', $aOldValue))
                                $nYFrom = $aOldValue['def_year_from'];
                            if (array_key_exists('def_year_to', $aOldValue))
                                $nYTo = $aOldValue['def_year_to'];
                        }
                    }
                    $this->aData[$key.'_day_from']   =  $nDFrom;
                    $this->aData[$key.'_day_to']     =  $nDTo;
                    $this->aData[$key.'_month_from'] =  $nMFrom;
                    $this->aData[$key.'_month_to']   =  $nMTo;
                    $this->aData[$key.'_year_from']  =  $nYFrom;
                    $this->aData[$key.'_year_to']    =  $nYTo;
                    break;
                case 'range':
                    $this->aData[$key.'_from'] =  (is_array($aOldValue) && array_key_exists('def_from',$aOldValue)) ? $aOldValue['def_from'] : '';
                    $this->aData[$key.'_to'] =  (is_array($aOldValue) && array_key_exists('def_to',$aOldValue)) ? $aOldValue['def_to'] : '';
                    break;
                default:
                    if (is_array($aOldValue) && array_key_exists('def',$aOldValue)) 
                    {
                        $this->aData[$key] = $aOldValue['def'];
                    }
                    else
                    {
                        $this->aData[$key] = '';
                    }
                    break;
            }
        }
        $this->set($this->aData);
    }
    
    /**
     * Prepares external conditions into internal language
     *
     */
    function _prepareConditions()
    {
        foreach ($this->aConditions as $key=>$value)
        {
            if (is_array($value)) $value = $value['value'];
            switch (strtolower($value))
            {
                case 'like':
                    $value = '{#'.$key.'} LIKE "%{$'.$key.'}%"';
                    if (array_key_exists($key, $this->aData))
                    {
                        if (trim($this->aData[$key]) == "") $value = "";
                    }
                    break;
                case '=':
                case '>':
                case '<':
                case '<>':
                case '>=':
                case '<=':
                    $value = '{#'.$key.'} '.$value.' "{$'.$key.'}"';
                    if (array_key_exists($key, $this->aData))
                    {
                        if (trim($this->aData[$key]) == "") $value = "";
                    }
                    break;
                case 'date':
                    if (array_key_exists($key, $this->aData) && $this->aData[$key] != "")
                    {
                        $value = '(DATE_FORMAT({#'.$key.'}, "%Y-%m-%d") = "{$'.$key.'}") ';
                    }
                    break;
                case 'date_range':
                case 'range':
                    $value = "";
                    $bFound = false;
                    if (array_key_exists($key.'_from', $this->aData) && $this->aData[$key.'_from'] != "")
                    {
                        $value .= '({#'.$key.'} >= "{$'.$key.'_from}") ';
                        $bFound = true;
                    }
                    if (array_key_exists($key.'_to', $this->aData) & $this->aData[$key.'_to'] != "")
                    {
                        if ($bFound) $value .= ' AND ';
                        $value .= '({#'.$key.'} <= "{$'.$key.'_to}") ';
                    }
                break;
                    
            }
            $this->aConditions[$key] = $value;
            if ($value == "") unset($this->aConditions[$key]);
        }
    }
    
    /**
     * Prepares html inputs in $aHtml
     *
     */
    function _prepareHtml()
    {
        $this->aHtml = array();
        foreach ($this->aConditions as $key=>$value)
        {
            $aOldValues = $value;
            if (is_array($value)) $value = $value['value'];
            switch (strtolower($value))
            {
                default:
                    if (!array_key_exists($key, $this->aData)) $this->aData[$key] = "";
                    if (is_array($aOldValues) && array_key_exists('select', $aOldValues))
                    {
                        $this->aHtml[$key]['type'] = 'select';
                        $this->aHtml[$key]['params']['name'] = $this->sFilterName.'['.$key.']';
                        if (is_array($aOldValues['select']))
                        {
                            foreach ($aOldValues['select'] as $key5 => $value5)
                            {
                                settype($key5,'string');
                                settype($this->aData[$key],'string');
                                $this->aHtml[$key]['select'][htmlspecialchars($key5)] = $value5;
                            }
                            if (($this->aData[$key] == '') && isset($aOldValues['def']))
                            {
                                $this->aHtml[$key]['value'] = $aOldValues['def'];
                            }
                            else
                            {
                            	$this->aHtml[$key]['value'] = $this->aData[$key];
                            }
                        }
                    }
                    else
                    {
                        $this->aHtml[$key]['type'] = 'text';
                        $this->aHtml[$key]['params']['name'] = $this->sFilterName.'['.$key.']';
                        $this->aHtml[$key]['value'] = $this->aData[$key];
                    }
                    break;
                case 'date':
                    if (!array_key_exists($key.'_day', $this->aData)) $this->aData[$key.'_day'] = date('d');
                    if (!array_key_exists($key.'_month', $this->aData)) $this->aData[$key.'_month'] = date('n');
                    if (!array_key_exists($key.'_year', $this->aData)) $this->aData[$key.'_year'] = date('Y');
                    $this->aHtml[$key.'_month']['type']  = 'select';
                    $this->aHtml[$key.'_month']['params']['name']  = $this->sFilterName.'['.$key.'_month]';
                    $this->aHtml[$key.'_month']['value'] = $this->aData[$key.'_month'];
                    for ($i=1;$i<=12;$i++)
                    {
                        $month_name = strftime('%B', mktime(0, 0, 0, $i, 1, 2000));
                        $this->aHtml[$key.'_month']['select'][$i] = $month_name;
                    }
                    $this->aHtml[$key.'_day']['type']  = 'select';
                    $this->aHtml[$key.'_day']['params']['name']  = $this->sFilterName.'['.$key.'_day]';
                    $this->aHtml[$key.'_day']['value'] = $this->aData[$key.'_day'];
                    for ($i=1;$i<=31;$i++)
                    {
                        $this->aHtml[$key.'_day']['select'][$i] = $i;
                    }
                    $this->aHtml[$key.'_year']['type']  = 'select';
                    $this->aHtml[$key.'_year']['params']['name']  = $this->sFilterName.'['.$key.'_year]';
                    $this->aHtml[$key.'_year']['value'] = $this->aData[$key.'_year'];
                    $start_i = date('Y') - $this->iYearPeriod;
                    $end_i = date('Y') + $this->iYearPeriod;
                    for ($i=$start_i; $i<$end_i; $i++)
                    {
                        $this->aHtml[$key.'_year']['select'][$i] = $i;
                    }
                    $this->aData[$key] = $this->_makeOnlyDate($this->aData[$key.'_year'], $this->aData[$key.'_month'], $this->aData[$key.'_day'], 0, 0, 0);
                    break;
                case 'date_range':
                    if (!array_key_exists($key.'_period', $this->aData)) $this->aData[$key.'_period'] = 0;
                    if (!array_key_exists($key.'_day_from', $this->aData)) $this->aData[$key.'_day_from'] = 1;
                    if (!array_key_exists($key.'_day_to', $this->aData)) $this->aData[$key.'_day_to'] = 31;
                    if (!array_key_exists($key.'_month_from', $this->aData)) $this->aData[$key.'_month_from'] = date('m');
                    if (!array_key_exists($key.'_month_to', $this->aData)) $this->aData[$key.'_month_to'] = date('m');
                    if (!array_key_exists($key.'_year_from', $this->aData)) $this->aData[$key.'_year_from'] = date('Y');
                    if (!array_key_exists($key.'_year_to', $this->aData)) $this->aData[$key.'_year_to'] = date('Y');
                    $iPeriod = (strpos($this->aData[$key.'_period'], ' ') === false ? 0 : substr($this->aData[$key.'_period'], 0, strpos($this->aData[$key.'_period'], ' ')));
                    $this->aHtml[$key.'_period']['type'] = 'select';
                    $this->aHtml[$key.'_period']['params']['name'] = $this->sFilterName.'['.$key.'_period]';
                    $this->aHtml[$key.'_period']['params']['onchange'] = 'updateDates(this.selectedIndex, \''.$this->sFilterName.'['.$key.'\', \']\')';
                    $this->aHtml[$key.'_period']['value'] = $iPeriod;
                    foreach ($this->aPeriods as $key1=>$value1)
                    {
                        $sValue = '';
                        if ($value1['from'] != '')
                        {
                            $nDTo   = date('d',strtotime($value1['to']));
                            $nDFrom = date('d',strtotime($value1['from'], strtotime($value1['to'])));
                            $nMFrom = date('m',strtotime($value1['from'], strtotime($value1['to'])));
                            $nMTo   = date('m',strtotime($value1['to']));
                            $nYFrom = date('Y',strtotime($value1['from'], strtotime($value1['to'])));
                            $nYTo   = date('Y',strtotime($value1['to']));
                            $sValue = $key1.' '.$nDFrom.' '.$nMFrom.' '.$nYFrom.' '.$nDTo.' '.$nMTo.' '.$nYTo;
                        }
                        $this->aHtml[$key.'_period']['select'][$sValue] .= $value1['name'];
                    }
                    $aTmp = array('from', 'to');
                    $this->aData[$key.'_from'] = $this->_makeDate($this->aData[$key.'_year_from'], $this->aData[$key.'_month_from'], $this->aData[$key.'_day_from'], 0, 0, 0);
                    $this->aData[$key.'_to'] = $this->_makeDate($this->aData[$key.'_year_to'], $this->aData[$key.'_month_to'], $this->aData[$key.'_day_to'], 23, 59, 59);
                    
                    foreach ($aTmp as $key1 => $value1)
                    {
                        $d = strtotime($this->aData[$key.'_'.$value1]);
                        $this->aData[$key.'_month_'.$value1] = date('m', $d);
                        $this->aData[$key.'_year_'.$value1] = date('Y', $d);
                        $this->aData[$key.'_day_'.$value1] = date('d', $d);

                        $this->aHtml[$key.'_month_'.$value1]['params']['name'] = $this->sFilterName.'['.$key.'_month_'.$value1.']';
                        $this->aHtml[$key.'_month_'.$value1]['type'] = 'select';
                        $this->aHtml[$key.'_month_'.$value1]['params']['id'] = $this->sFilterName.'['.$key.'_month_'.$value1.']';
                        $this->aHtml[$key.'_month_'.$value1]['params']['onchange'] = 'resetPeriod(\''.$this->sFilterName.'['.$key.'\', \']\')';
                        $this->aHtml[$key.'_month_'.$value1]['value'] = $this->aData[$key.'_month_'.$value1];
                        for ($i=1;$i<=12;$i++)
                        {
                            $month_name = strftime('%B', mktime(0, 0, 0, $i, 1, 2000));
                            $this->aHtml[$key.'_month_'.$value1]['select'][$i] = $month_name;
                        }

                        $this->aHtml[$key.'_day_'.$value1]['type'] = 'select';
                        $this->aHtml[$key.'_day_'.$value1]['value'] = $this->aData[$key.'_day_'.$value1];
                        $this->aHtml[$key.'_day_'.$value1]['params']['name'] = $this->sFilterName.'['.$key.'_day_'.$value1.']';
                        $this->aHtml[$key.'_day_'.$value1]['params']['id'] = $this->sFilterName.'['.$key.'_day_'.$value1.']';
                        $this->aHtml[$key.'_day_'.$value1]['params']['onchange'] = 'resetPeriod(\''.$this->sFilterName.'['.$key.'\', \']\')';
                        for ($i=1;$i<=31;$i++)
                        {
                            $this->aHtml[$key.'_day_'.$value1]['select'][$i] = $i;
                        }

                        $this->aHtml[$key.'_year_'.$value1]['type'] = 'select';
                        $this->aHtml[$key.'_year_'.$value1]['value'] = $this->aData[$key.'_year_'.$value1];
                        $this->aHtml[$key.'_year_'.$value1]['params']['name'] = $this->sFilterName.'['.$key.'_year_'.$value1.']';
                        $this->aHtml[$key.'_year_'.$value1]['params']['id'] = $this->sFilterName.'['.$key.'_year_'.$value1.']';
                        $this->aHtml[$key.'_year_'.$value1]['params']['onchange'] = 'resetPeriod(\''.$this->sFilterName.'['.$key.'\', \']\')';
                        $start_i = date('Y')-$this->iYearPeriod;
                        $end_i = date('Y')+$this->iYearPeriod;
                        for ($i=$start_i;$i<$end_i;$i++)
                        {
                            $this->aHtml[$key.'_year_'.$value1]['select'][$i] = $i;
                        }
                    }
                    break;
                case 'range':
                    if (!array_key_exists($key.'_from', $this->aData)) $this->aData[$key.'_from'] = "";
                    if (!array_key_exists($key.'_to', $this->aData)) $this->aData[$key.'_to'] = "";

                    if (!array_key_exists('select', $aOldValues))
                    {
                        $this->aHtml[$key.'_from']['type'] = 'text';
                        $this->aHtml[$key.'_to']['type'] = 'text';
                    }
                    else
                    {
                        $this->aHtml[$key.'_from']['type'] = 'select';
                        $this->aHtml[$key.'_to']['type'] = 'select';
                        $this->aHtml[$key.'_from']['select'] = $aOldValues['select'];
                        $this->aHtml[$key.'_to']['select'] = $aOldValues['select'];
                    }

                    $this->aHtml[$key.'_from']['value'] = htmlspecialchars($this->aData[$key.'_from']);
                    $this->aHtml[$key.'_from']['params']['name'] = $this->sFilterName.'['.$key.'_from]';

                    $this->aHtml[$key.'_to']['value'] = $this->aData[$key.'_to'];
                    $this->aHtml[$key.'_to']['params']['name'] = $this->sFilterName.'['.$key.'_to]';
                    break;
            }
        }
    }
    
    /** Compile filter date as string from separate calues
     * @param int $iYear  year
     * @param int $iMonth month
     * @param int $iDay   day
     * @param int $iHour  hour
     * @param int $iMin   minute
     * @param int $iSec   second
     * @return string formatted data
     */
    function _makeDate($iYear, $iMonth=1, $iDay=1, $iHour=0, $iMin=0, $iSec=0) 
    {
        $sDate = date('Y-m-d H:i:s', mktime($iHour, $iMin, $iSec, $iMonth, $iDay, $iYear));
        return $sDate;
    }    

    /** Compile filter date as string from separate calues
     * @param int $iYear  year
     * @param int $iMonth month
     * @param int $iDay   day
     * @return string formatted data
     */
    function _makeOnlyDate($iYear, $iMonth=1, $iDay=1) 
    {
        $sDate = date('Y-m-d', mktime(0, 0, 0, $iMonth, $iDay, $iYear));
        return $sDate;
    }    
    
    
}

?>